#include "dtwentymodel.h"
#include "dtwentyitem.h"
#include "campaign.h"
#include "characterclass.h"


#include <QDebug>
#include <QTimer>
#include <QMetaProperty>


DTwentyModel::DTwentyModel(QObject *parent) :
    ItemTreeModel(parent)
{
    qRegisterMetaType<DTwentyItem*>();
}

QVariant DTwentyModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
    {
        return ItemTreeModel::data(index, role);
    }

    if (role < Role_FIRST)
    {
        return ItemTreeModel::data(index, role);
    }

    DTwentyItem* item = itemFromIndex(index);
    if (!item)
    {
        return ItemTreeModel::data(index, role);
    }

    const QMetaObject* mo = item->metaObject();
    int col = index.column();

    if (!mo)
    {
        return ItemTreeModel::data(index, role);
    }



    DTwentyItemContainer* container = qobject_cast<DTwentyItemContainer*>(item);

    switch (role)
    {
    case Role_DTWENTY_BASETYPE:
    {
        if (!container)
        {
            return DTwentyBaseType_ITEM;
        }
        return DTwentyBaseType_CONTAINER;
    }

    case Role_CHILD_TYPE:
    {
        if (!container)
        {
            return QVariant();
        }

        int type = container->childType();
        if (type < 0)
        {
            return QVariant();
        }

        return type;
    }
    case Role_CHILD_TYPENAME:
    {
        if (!container)
        {
            return QVariant();
        }

        QString ret = container->childTypeName();
        if (ret.isEmpty())
        {
            return QVariant();
        }

        return ret;
    }
    case Role_VALUE_TYPE:
    {
        QMetaProperty mp = mo->property(col+1);
        if (mp.isEnumType())
        {
            return ValueType_SELECTION;
        }

        DTwentyItemContainer* optionsContainer = qobject_cast<DTwentyItemContainer*>(item->parent());
        if (optionsContainer && optionsContainer->valueSource())
        {
            return ValueType_SELECTION;
        }

        return ValueType_NORMAL;
    }
    case Role_VALUE_SOURCE:
    {
        if (!container)
        {
            return QVariant();
        }
        return QVariant::fromValue<DTwentyItemContainer*>(container->valueSource());
    }
    case Role_VALUE_OPTIONS:
    {
        QMetaProperty mp = mo->property(col+1);
        if (mp.isEnumType())
        {
            QVariantMap ret;

            QMetaEnum me = mp.enumerator();
            for (int i = 0; i < me.keyCount(); i++)
            {
                ret.insert(me.key(i), me.value(i));
            }
            return ret;
        }

        DTwentyItemContainer* optionsContainer = qobject_cast<DTwentyItemContainer*>(item->parent());
        if (optionsContainer)
        {
            return optionsContainer->valueOptions();
        }

        return QVariantMap();

    }
    default:
        break;
    }

    return QVariant();
}

QVariant DTwentyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    Q_UNUSED(orientation)

    if (role != Qt::DisplayRole)
    {
        return QVariant();
    }

    if (section == 0)
    {
        return tr("Name");
    }

    return QString();
}

bool DTwentyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!index.isValid() || value.isNull())
    {
        return false;
    }

    if (role != DTwentyModel::Role_VALUE_OPTIONS)
    {
        return ItemTreeModel::setData(index, value, role);
    }

    DTwentyItem* item = itemFromIndex(index);
    if (!item)
    {
        return false;
    }

    DTwentyItem* refItem = qvariant_cast<DTwentyItem*>(value);
    if (!refItem)
    {
        return ItemTreeModel::setData(index, value, Qt::EditRole);
    }

    item->setReferenceItem(refItem);
    return true;
}

bool DTwentyModel::insertRows(int row, int count, const QModelIndex &parent)
{
    if (!parent.isValid())
    {
        return false;
    }

    DTwentyItemContainer* containerItem = containerFromIndex(parent);
    if (!containerItem)
    {
        return false;
    }

    int oldColumns = columnCount(parent);
    int newColumns = oldColumns;

    beginInsertRows(parent, row, row+count-1);

    for (int i = 0; i < count; i++)
    {
        QString name = tr("New");
        QString typeName = containerItem->childTypeName();
        if (!typeName.isEmpty())
        {
            name = QString("%1 %2").arg(name).arg(typeName);
        }
        DTwentyItem* child = containerItem->newChild(name);

        const QMetaObject* mo = child->metaObject();

        int properties = mo->propertyCount() - 1;
        if (properties > newColumns)
        {
            newColumns = properties;
        }
    }

    endInsertRows();

    if (newColumns > oldColumns)
    {
        QTimer::singleShot(0, this, SIGNAL(layoutAboutToBeChanged()));
        beginInsertColumns(parent, oldColumns, newColumns-1);
        endInsertColumns();
        QTimer::singleShot(0, this, SIGNAL(layoutChanged()));
    }

    return true;

}

bool DTwentyModel::removeRows(int row, int count, const QModelIndex &parent)
{
    Q_UNUSED(count)

    DTwentyItem* parentItem = 0;
    if (!parent.isValid())
    {
        parentItem = qobject_cast<DTwentyItem*>(root());
    }
    else
    {
        parentItem = itemFromIndex(parent);
    }

    if (!parentItem)
    {
        return false;
    }

    QList<DTwentyItem*> items = parentItem->findChildren<DTwentyItem*>(QString(), Qt::FindDirectChildrenOnly);
    if (row < 0 || row >= items.count())
    {
        return false;
    }


    DTwentyItem* item = items.at(row);
    if (!item || !item->removable())
    {
        return false;
    }

    int oldColumns = columnCount(QModelIndex());

    beginRemoveRows(parent, row, row);
    item->setParent(0);
    item->deleteLater();
    endRemoveRows();

    int newColums = columnCount(QModelIndex());

    if (oldColumns > newColums)
    {
        QTimer::singleShot(0, this, SIGNAL(layoutAboutToBeChanged()));

        beginRemoveColumns(QModelIndex(), newColums, oldColumns-1);
        endRemoveColumns();

        QTimer::singleShot(0, this, SIGNAL(layoutChanged()));
    }

    return true;
}

Qt::ItemFlags DTwentyModel::flags(const QModelIndex &index) const
{
    DTwentyItemContainer* container = containerFromIndex(index);
    if (container)
    {
        return QAbstractItemModel::flags(index);
    }

    return ItemTreeModel::flags(index);
}

QVariantMap DTwentyModel::characterClasses() const
{
    if (!root())
    {
        return QVariantMap();
    }

    QVariantMap ret;
    foreach (CharacterClass* cc, root()->findChildren<CharacterClass*>())
    {
        ret.insert(cc->name(), QVariant::fromValue<CharacterClass*>(cc));
    }

    return ret;
}


DTwentyItem *DTwentyModel::itemFromIndex(const QModelIndex &index)
{
    return qobject_cast<DTwentyItem*>(ItemTreeModel::itemFromIndex(index));
}

DTwentyItemContainer *DTwentyModel::containerFromIndex(const QModelIndex &index)
{
    return qobject_cast<DTwentyItemContainer*>(ItemTreeModel::itemFromIndex(index));
}

QString DTwentyModel::propertyName(const QModelIndex &index)
{
    DTwentyItem* item = itemFromIndex(index);
    if (!item)
    {
        return QString();
    }

    const QMetaObject* mo = item->metaObject();
    if (!mo || mo->propertyCount() <= 1)
    {
        return QString();
    }

    int propertyIndex = index.column()+1;
    if (propertyIndex >= mo->propertyCount())
    {
        return QString();
    }

    QMetaProperty mp = mo->property(propertyIndex);
    return mp.name();
}

